

#include <stm32f4xx_hal.h>
#include <rtthread.h>
#include <bsp_i2c.h>
#include <sensor_ina226.h>

static rt_device_t ina226_current_dev = RT_NULL;
static struct ina226_sensor_info ina226_info;

static int
bsp_ina226_init(void);

/* device interface */
static rt_err_t rt_ina226_open(rt_device_t dev, rt_uint16_t oflag);
static rt_err_t rt_ina226_close(rt_device_t dev);
static rt_size_t rt_ina226_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
static rt_size_t rt_ina226_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
static rt_err_t rt_ina226_control(rt_device_t dev, int cmd, void *args);

/// @brief 读取INA226的ID号，检查是否通信正常
/// @return 通过返回0
static int ina226_read_id()
{
    I2C_HandleTypeDef *i2c_sensor = bsp_sensor_i2c_handle();
    uint8_t id_arr[2];
    HAL_I2C_Mem_Read(i2c_sensor, INA226_ADDR, INA226_READ_ID, I2C_MEMADD_SIZE_8BIT, id_arr, 2, 10);
    if (id_arr[0] != (INA226_ID >> 8) || id_arr[1] != (INA226_ID & 0xff))
    {
        rt_kprintf("error happened when read ina226 id, rslt is %02x %02x, expect is %02x\n", id_arr[0], id_arr[1], INA226_ID);
        return -1;
    }

    return 0;
}

/// @brief 配置INA226传感器
/// @param
/// @return
static int ina226_config(void)
{
    I2C_HandleTypeDef *i2c_sensor = bsp_sensor_i2c_handle();
    static uint8_t cmd_u8[2];

    /* 先发送高字节 */
    cmd_u8[0] = 0x45;
    cmd_u8[1] = 0x67;

    HAL_StatusTypeDef rslt = HAL_I2C_Mem_Write(i2c_sensor, INA226_ADDR, INA226_CONFIG, I2C_MEMADD_SIZE_8BIT, cmd_u8, 2, 10);
    if (rslt != HAL_OK)
        return -1;

    /* 测量最大范围 */
    float range_max_float = 0.00512f / (MAX_EXPECT_CURRENT / 32768) / SHUNT_RESISTOR_OM;
    uint16_t range_max_val = range_max_float * 1.2f;

    cmd_u8[0] = range_max_val >> 8;
    cmd_u8[1] = range_max_val & 0XFF;

    rslt = HAL_I2C_Mem_Write(i2c_sensor, INA226_ADDR, INA226_CALIB, I2C_MEMADD_SIZE_8BIT, cmd_u8, 2, 10);
    if (rslt != HAL_OK)
        return -1;

    return 0;
}

int rt_ina226_sensor_register(void)
{
    static rt_uint8_t ina226_dev_register_passed = 0;
    if (ina226_dev_register_passed != 0)
        return RT_EOK;

    /* construct device */
    ina226_current_dev = rt_device_create(RT_Object_Class_Device, 0);
    if (ina226_current_dev == RT_NULL)
    {
        rt_kprintf("error happened when create ina226 current device\n");
        return RT_ENOMEM;
    }

    /* set device function pointer */
    ina226_current_dev->init = RT_NULL;
    ina226_current_dev->open = rt_ina226_open;
    ina226_current_dev->close = rt_ina226_close;
    ina226_current_dev->read = rt_ina226_read;
    ina226_current_dev->write = rt_ina226_write;
    ina226_current_dev->control = rt_ina226_control;

    /* register device */
    rt_err_t rslt1 = rt_device_register(ina226_current_dev, "ina226_current", RT_DEVICE_FLAG_RDWR);

    if (rslt1 != RT_EOK)
    {
        rt_kprintf("error happened when register ina226 current device, rslt = %d\n", rslt1);
    }

    int rslt = bsp_ina226_init();
    if (rslt == RT_EOK)
    {
        ina226_dev_register_passed = 1;
    }

    return rslt;
}

int bsp_ina226_init(void)
{
    int rslt = bsp_sensor_i2c_init();
    if (rslt != 0)
    {
        return rslt;
    }

    /* read register to test I2C link */
    rslt = ina226_read_id();
    if (rslt != 0)
    {
        return rslt;
    }

    /* cofig INA226 sensor */
    rslt = ina226_config();
    if (rslt != 0)
    {
        return rslt;
    }

    return 0;
}

rt_err_t rt_ina226_open(rt_device_t dev, rt_uint16_t oflag)
{
    if (dev == RT_NULL || dev != ina226_current_dev)
    {
        rt_kprintf("ina226 open failed for device pointer not correct\n");
        return RT_ERROR;
    }

    I2C_HandleTypeDef *ina226_i2c_handle = bsp_sensor_i2c_handle();
    if (ina226_i2c_handle)
        __HAL_I2C_ENABLE(ina226_i2c_handle);

    return RT_EOK;
}

static rt_err_t rt_ina226_close(rt_device_t dev)
{
    if (dev == RT_NULL || dev != ina226_current_dev)
    {
        rt_kprintf("ina226 close failed for device pointer not correct\n");
        return RT_ERROR;
    }

    I2C_HandleTypeDef *ina226_i2c_handle = bsp_sensor_i2c_handle();
    if (ina226_i2c_handle)
        __HAL_I2C_DISABLE(ina226_i2c_handle);

    return RT_EOK;
}

static rt_size_t rt_ina226_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    if (dev == RT_NULL || dev != ina226_current_dev)
    {
        rt_kprintf("ina226 read failed for device pointer not correct\n");
        return -RT_ERROR;
    }

    /* Read Bus Voltage and Current from INA226 register */
    I2C_HandleTypeDef *ina226_i2c_handle = bsp_sensor_i2c_handle();
    int16_t reg_val;
    HAL_I2C_Mem_Read(ina226_i2c_handle, INA226_ADDR, INA226_BUS_VOLTAGE, I2C_MEMADD_SIZE_8BIT,
                     (uint8_t *)(&reg_val), sizeof(reg_val), 10);

    ina226_info.bus_voltage = 1.25f * reg_val;

    HAL_I2C_Mem_Read(ina226_i2c_handle, INA226_ADDR, INA226_SHUNT_VOLTAGE, I2C_MEMADD_SIZE_8BIT,
                     (uint8_t *)(&reg_val), sizeof(reg_val), 10);

    ina226_info.shunt_voltage = 2.5f * 0.001f * reg_val;

    HAL_I2C_Mem_Read(ina226_i2c_handle, INA226_ADDR, INA226_CURRENT, I2C_MEMADD_SIZE_8BIT,
                     (uint8_t *)(&reg_val), sizeof(reg_val), 10);

    ina226_info.current = 0.02f * reg_val;

    HAL_I2C_Mem_Read(ina226_i2c_handle, INA226_ADDR, INA226_POWER, I2C_MEMADD_SIZE_8BIT,
                     (uint8_t *)(&reg_val), sizeof(reg_val), 10);

    ina226_info.power = 0.02f * 25 * reg_val;

    return sizeof(ina226_info);
}

static rt_size_t rt_ina226_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    if (dev == RT_NULL || dev != ina226_current_dev)
    {
        rt_kprintf("ina226 write failed for device pointer not correct\n");
        return -RT_ERROR;
    }

    I2C_HandleTypeDef *ina226_i2c_handle = bsp_sensor_i2c_handle();

    HAL_I2C_Mem_Write(ina226_i2c_handle, INA226_ADDR, (uint16_t)pos, I2C_MEMADD_SIZE_8BIT,
                      (uint8_t *)buffer, size, size * 10);
    return size;
}

static rt_err_t rt_ina226_control(rt_device_t dev, int cmd, void *args)
{
    return RT_EOK;
}
